#include "wx/wxprec.h"

#ifdef wxHAS_TASK_BAR_ICON
#include "wx/taskbar.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <gtk/gtk.h>
#include "wx/gtk/taskbarpriv.h"

#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#define GetDisplay() GDK_DISPLAY()
#define GetXWindow(wxwin) GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)

class wxTaskBarIconArea : public wxTaskBarIconAreaBase {
  public:
    wxTaskBarIconArea( wxTaskBarIcon *icon, const wxBitmap &bmp );
    void SetTrayIcon( const wxBitmap& bmp );
    bool IsOk() { return true; }
  protected:
    void SetLegacyWMProperties();
    void OnSizeChange( wxSizeEvent& event );
    void OnPaint( wxPaintEvent& evt );
    void OnMouseEvent( wxMouseEvent& event );
    void OnMenuEvent( wxCommandEvent& event );
    wxTaskBarIcon *m_icon;
    wxPoint        m_pos;
    wxBitmap       m_bmp;
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( wxTaskBarIconArea, wxTaskBarIconAreaBase )
  EVT_SIZE( wxTaskBarIconArea::OnSizeChange )
  EVT_MOUSE_EVENTS( wxTaskBarIconArea::OnMouseEvent )
  EVT_MENU( wxID_ANY, wxTaskBarIconArea::OnMenuEvent )
  EVT_PAINT( wxTaskBarIconArea::OnPaint )
END_EVENT_TABLE()

wxTaskBarIconArea::wxTaskBarIconArea( wxTaskBarIcon *icon, const wxBitmap &bmp )
  : wxTaskBarIconAreaBase(), m_icon( icon ), m_pos( 0, 0 ) {
  m_invokingWindow = icon;
  SetClientSize( wxSize( bmp.GetWidth(), bmp.GetHeight() ) );
  SetTrayIcon( bmp );
  if( !IsProtocolSupported() ) {
    wxLogTrace( _T( "systray" ), _T( "using legacy KDE1,2 and GNOME 1.2 methods" ) );
    SetLegacyWMProperties();
  }
}

void wxTaskBarIconArea::SetTrayIcon( const wxBitmap& bmp ) {
  m_bmp = bmp;
  // determine suitable bitmap size:
  wxSize winsize( GetClientSize() );
  wxSize bmpsize( m_bmp.GetWidth(), m_bmp.GetHeight() );
  wxSize iconsize( wxMin( winsize.x, bmpsize.x ), wxMin( winsize.y, bmpsize.y ) );
  // rescale the bitmap to fit into the tray icon window:
  if( bmpsize != iconsize ) {
    wxImage img = m_bmp.ConvertToImage();
    img.Rescale( iconsize.x, iconsize.y );
    m_bmp = wxBitmap( img );
  }
  wxRegion region;
  region.Union( m_bmp );
  // if the bitmap is smaller than the window, offset it:
  if( winsize != iconsize ) {
    m_pos.x = ( winsize.x - iconsize.x ) / 2;
    m_pos.y = ( winsize.y - iconsize.y ) / 2;
    region.Offset( m_pos.x, m_pos.y );
  }
  // set frame's shape to correct value and redraw:
  SetShape( region );
  Refresh();
}

void wxTaskBarIconArea::SetLegacyWMProperties() {
  gtk_widget_realize( m_widget );
  long data[1];
  // KDE 2 & KDE 3:
  Atom _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR =
    XInternAtom( GetDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
  data[0] = 0;
  XChangeProperty( GetDisplay(), GetXWindow( this ),
                   _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
                   XA_WINDOW, 32,
                   PropModeReplace, ( unsigned char* )data, 1 );
  // GNOME 1.2 & KDE 1:
  Atom KWM_DOCKWINDOW =
    XInternAtom( GetDisplay(), "KWM_DOCKWINDOW", False );
  data[0] = 1;
  XChangeProperty( GetDisplay(), GetXWindow( this ),
                   KWM_DOCKWINDOW,
                   KWM_DOCKWINDOW, 32,
                   PropModeReplace, ( unsigned char* )data, 1 );
}

void wxTaskBarIconArea::OnSizeChange( wxSizeEvent & ( event ) ) {
  wxLogTrace( _T( "systray" ), _T( "icon size changed to %i x %i" ),
              GetSize().x, GetSize().y );
  // rescale or reposition the icon as needed:
  wxBitmap bmp( m_bmp );
  SetTrayIcon( bmp );
}

void wxTaskBarIconArea::OnPaint( wxPaintEvent & ( event ) ) {
  wxPaintDC dc( this );
  dc.DrawBitmap( m_bmp, m_pos.x, m_pos.y, true );
}

void wxTaskBarIconArea::OnMouseEvent( wxMouseEvent& event ) {
  wxEventType type = 0;
  wxEventType mtype = event.GetEventType();
  if( mtype == wxEVT_LEFT_DOWN ) {
    type = wxEVT_TASKBAR_LEFT_DOWN;
  } else if( mtype == wxEVT_LEFT_UP ) {
    type = wxEVT_TASKBAR_LEFT_UP;
  } else if( mtype == wxEVT_LEFT_DCLICK ) {
    type = wxEVT_TASKBAR_LEFT_DCLICK;
  } else if( mtype == wxEVT_RIGHT_DOWN ) {
    type = wxEVT_TASKBAR_RIGHT_DOWN;
  } else if( mtype == wxEVT_RIGHT_UP ) {
    type = wxEVT_TASKBAR_RIGHT_UP;
  } else if( mtype == wxEVT_RIGHT_DCLICK ) {
    type = wxEVT_TASKBAR_RIGHT_DCLICK;
  } else if( mtype == wxEVT_MOTION ) {
    type = wxEVT_TASKBAR_MOVE;
  } else
  { return; }
  wxTaskBarIconEvent e( type, m_icon );
  m_icon->ProcessEvent( e );
}

void wxTaskBarIconArea::OnMenuEvent( wxCommandEvent& event ) {
  m_icon->ProcessEvent( event );
}

// ----------------------------------------------------------------------------
// wxTaskBarIcon class:
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS( wxTaskBarIcon, wxEvtHandler )

wxTaskBarIcon::wxTaskBarIcon() : m_iconWnd( NULL ) {
}

wxTaskBarIcon::~wxTaskBarIcon() {
  if( m_iconWnd ) {
    m_iconWnd->Disconnect( wxEVT_DESTROY, ( wxObjectEventFunction )NULL,
                           ( wxObject* )NULL, this );
    RemoveIcon();
  }
}

bool wxTaskBarIcon::IsOk() const {
  return true;
}

bool wxTaskBarIcon::IsIconInstalled() const {
  return m_iconWnd != NULL;
}

// Destroy event from wxTaskBarIconArea
void wxTaskBarIcon::OnDestroy( wxWindowDestroyEvent& ) {
  // prevent crash if wxTaskBarIconArea is destroyed by something else,
  // for example if panel/kicker is killed
  m_iconWnd = NULL;
}

bool wxTaskBarIcon::SetIcon( const wxIcon& icon, const wxString& tooltip ) {
  wxBitmap bmp;
  bmp.CopyFromIcon( icon );
  if( !m_iconWnd ) {
    m_iconWnd = new wxTaskBarIconArea( this, bmp );
    if( m_iconWnd->IsOk() ) {
      m_iconWnd->Connect( wxEVT_DESTROY,
                          wxWindowDestroyEventHandler( wxTaskBarIcon::OnDestroy ),
                          NULL, this );
      m_iconWnd->Show();
    } else {
      m_iconWnd->Destroy();
      m_iconWnd = NULL;
      return false;
    }
  } else
  { m_iconWnd->SetTrayIcon( bmp ); }
  #if wxUSE_TOOLTIPS
  if( !tooltip.empty() ) {
    m_iconWnd->SetToolTip( tooltip );
  } else
  { m_iconWnd->SetToolTip( NULL ); }
  #else
  wxUnusedVar( tooltip );
  #endif
  return true;
}

bool wxTaskBarIcon::RemoveIcon() {
  if( !m_iconWnd ) {
    return false;
  }
  m_iconWnd->Destroy();
  m_iconWnd = NULL;
  return true;
}

bool wxTaskBarIcon::PopupMenu( wxMenu *menu ) {
  if( !m_iconWnd ) {
    return false;
  }
  m_iconWnd->PopupMenu( menu );
  return true;
}

#endif // wxHAS_TASK_BAR_ICON
